package com.mocha.bss.domain.rbac.service;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.coffee.core.CoffeeException;
import com.coffee.core.CoffeeResponseEnum;
import com.coffee.core.JSONUtils;
import com.mocha.bss.domain.rbac.config.MochaFunctionManager;
import com.mocha.bss.domain.rbac.repository.entity.RoleFunctionEntity;
import com.mocha.bss.domain.rbac.repository.MochaRoleFunctionRepository;
import com.mocha.bss.feign.bo.menu.FunctionVO;
import com.mocha.bss.feign.bo.menu.PermissionVO;
import com.mocha.bss.rbac.vo.CoordinateVO;
import com.pinghua.mocha.basics.dmo.AdmdivTreeBO;
import com.pinghua.mocha.basics.dmo.RoleVO;
import com.pinghua.mocha.basics.dmo.UserRedisVO;
import com.pinghua.mocha.basics.setting.MochaSettings;
import com.pinghua.mocha.basics.setting.RedisKeyConstant;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j
@AllArgsConstructor
public class PermissionService {
    private final RedisTemplate<String, Object> redisTemplate;
    private final MochaRoleFunctionRepository mochaRoleFunctionRepository;

    public PermissionVO buildPermission(Long userId){
        log.info("Build permission userId {}", userId);

        String json = (String) redisTemplate.opsForHash().get(RedisKeyConstant.ORG_USER_MAP, userId);
        if (null == json){
            throw new CoffeeException(CoffeeResponseEnum.LoginFailed);
        }
        UserRedisVO userRedisVO = JSONUtils.parse(json, UserRedisVO.class);

        List<Long> roleIds = userRedisVO.getRoleList().stream().map(RoleVO::getId).collect(Collectors.toList());
        List<RoleFunctionEntity> functionEntities = mochaRoleFunctionRepository.listByRoleIds(roleIds);

        boolean isAll = checkIsAll(functionEntities);
        Set<FunctionVO> functionSet = isAll ? new HashSet<>() : findFunctionCode(functionEntities);
        return PermissionVO.builder()
                .admdivTree(userRedisVO.getAdmdivTree())
                .funList(functionSet)
                .all(isAll)
                .build();
    }
    public CoordinateVO positioning(Long userId){
        log.info("Build positioning userId {}", userId);

        String json = (String) redisTemplate.opsForHash().get(RedisKeyConstant.ORG_USER_MAP, userId);
        if (null == json){
            throw new CoffeeException(CoffeeResponseEnum.LoginFailed);
        }
        UserRedisVO userRedisVO = JSONUtils.parse(json, UserRedisVO.class);
        AdmdivTreeBO admdivTreeBO = userRedisVO.getAdmdivTree();
        if (null != admdivTreeBO){
            return buildCoordinate(admdivTreeBO);
        }

        return new CoordinateVO();
    }

    private CoordinateVO buildCoordinate(AdmdivTreeBO admdivTreeBO){
         if (CollectionUtil.isEmpty(admdivTreeBO.getList()) || admdivTreeBO.getList().size() > 1){
             return new CoordinateVO(admdivTreeBO.getLat(), admdivTreeBO.getLng());
         }
         return buildCoordinate(admdivTreeBO.getList().get(0));
    }


    private boolean checkIsAll(List<RoleFunctionEntity> functionEntities){
        if (CollectionUtil.isEmpty(functionEntities)){
            log.error("Role not set function roleId");
           throw new CoffeeException(CoffeeResponseEnum.ParamInvalid);
        }
        for (RoleFunctionEntity roleFunctionEntity : functionEntities){
            if (roleFunctionEntity.getFunctionCode().contains(MochaSettings.ALL)){
                return true;
            }
        }

        return false;

    }

    private Set<FunctionVO> findFunctionCode(List<RoleFunctionEntity> functionEntities){
        Set<String> codes = setFunctionCode(functionEntities);
        return MochaFunctionManager.findVOByCodes(codes);
    }

    private Set<String> setFunctionCode(List<RoleFunctionEntity> functionEntities){
        Set<String> set = new HashSet<>();
        for (RoleFunctionEntity functionEntity : functionEntities){
            String code = functionEntity.getFunctionCode();
            if (StrUtil.isNotEmpty(code)){
                set.addAll(Arrays.stream(code.split("\\s*,\\s*"))
                        .filter(s -> !s.isEmpty())
                        .collect(Collectors.toSet()));
            }
        }

        return set;
    }
}
